/****************************************************************************
*                                                                           *
* scatter.h - scattering simulator											*
*                                                                           *
* ALaRI 2008												                *
*                                                                           *
****************************************************************************/
#pragma once

#if !defined(__SCATTER_H)
#define __SCATTER_H

/****************************************************************************
* Includes										                            *
****************************************************************************/
#include "scatmatrix.h"

#include <hash_map>

#include <QObject>
#include <QList>
#include <QImage>
#include <QFutureWatcher>

/****************************************************************************
* Forward declaration														*
****************************************************************************/
class QImage;
class QPoint;
class QString;
class QRect;

class CFloorPlan;
class CMaterial;
class CSensor;

/****************************************************************************
* __SScatKey - key for caching scattering matrices in CMap					*
****************************************************************************/
struct __SScatKey
{
	const CScatMatrix	*m_pLOrT;
	const CScatMatrix	*m_pROrB;
	bool				m_bHorizontal;
};

/****************************************************************************
* __SHashKey - hash function for __SScatKey structure						*
****************************************************************************/
struct __SKeyHasher
{
	size_t operator()(const __SScatKey& key) const 
	{
		return (size_t)((((DWORD_PTR)key.m_pLOrT) >> 3) + (((DWORD_PTR)key.m_pROrB) >> 3)) +
		(key.m_bHorizontal ? 1uL : 0uL);
	}
};

/****************************************************************************
* __SKeysComparator - compares two keys										*
****************************************************************************/
struct __SKeysComparator
{
	bool operator () (const __SScatKey& pElement1, const __SScatKey& pElement2) const
	{
		return pElement1.m_bHorizontal == pElement2.m_bHorizontal &&
		pElement1.m_pLOrT == pElement2.m_pLOrT &&
		pElement1.m_pROrB == pElement2.m_pROrB;
		return true;
	}
};

/****************************************************************************
* CScatSimulator - scattering parflow simulator								*
****************************************************************************/
class CScatSimulator : public QObject
{
	Q_OBJECT 

public:
	/****************************************************************************
	* Construction/Destruction													*
	****************************************************************************/
	CScatSimulator(const int& nWidth, const int& nHeight, const QImage& qImageFloor);
	~CScatSimulator();

	/****************************************************************************
	* Public																	*
	****************************************************************************/
	float getFieldAt(const QPoint& point, CMaterial *pMaterial) const;
	void updateField(unsigned int nSensorID); 
	
	// TODO: add public interface for simulation
	void runSimulation(bool bElaborate);
	void cancelSimulation();

signals :
	void doing(QString strWhat); 
	void simulationDone(); 

protected:

	/****************************************************************************
	* Protected data structures													*
	****************************************************************************/
	struct SSimPoint // simulation point contains 4 incoming flows
	{
		std::complex<float>	m_cfltIN;
		std::complex<float>	m_cfltIE;
		std::complex<float>	m_cfltIS;
		std::complex<float>	m_cfltIW;
	};

	/****************************************************************************
	* Protected workers															*
	****************************************************************************/
	const CScatMatrix *getScatMatrix(const QRect& rect);
	const CScatMatrix *getScatMatrixL0(const QPoint& point);
	void simulate(bool bElaborate);
	void elaborateFloorPlan();
	void putSensor(CSensor *pSensor); 
	void freeElaborationData();
	void allocateSimSpace();
	void freeSimSpace();
	void freeSimulationData();
	void phase1UpdateInnerFlows(const QRect& rect, const CScatMatrix *pMatrix);
	void phase1UpdateEquivalentSource(const QRect& rect, const CScatMatrix *pMatrix);
	void phase2UpdateInnerFlows(const QRect& rect, const CScatMatrix *pMatrix);
	float computeField(SSimPoint& simPoint, CMaterial *pMaterial) const; 
	/****************************************************************************
	* Protected data															*
	****************************************************************************/
	// simulation space
	SSimPoint			*m_pSS;
	// temporary buffers for calculations
	std::complex<float>	*m_pB1;
	std::complex<float>	*m_pB2;
	// width and height of the simulation area
	const int&			m_nWidth;
	const int&			m_nHeight;
	const QImage&		m_qImageFloor;
	// top level scattering matrix
	const CScatMatrix	*m_pScatMatrix;
	// cache of scattering matrices
	std::hash_map<__SScatKey, CScatMatrixLP*, __SKeyHasher, __SKeysComparator> m_mapScatMatrices;
private :
	QFutureWatcher<void>	m_simWatcher;	 
	bool					m_bCancelSimulation;
};

#endif /* __SCATTER_H */
/****************************************************************************
* End of file																*
****************************************************************************/
